#include "include.h"

static const char *TAG = "app_camera";

#define CAM_P (2)

#define CAM_WIDTH (320)
#define CAM_HIGH (240)
#define IMAGE_BUF_SIZE (30 * 1024)

extern EventGroupHandle_t app_event_handle;

void cam_task(void *arg)
{
    cam_config_t cam_config = {
        .bit_width = 8,
        .mode.jpeg = 1,
        .xclk_fre = 16 * 1000 * 1000,
        .pin = {
            .xclk = CAM_XCLK,
            .pclk = CAM_PCLK,
            .vsync = CAM_VSYNC,
            .hsync = CAM_HSYNC,
        },
        .pin_data = {CAM_D0, CAM_D1, CAM_D2, CAM_D3, CAM_D4, CAM_D5, CAM_D6, CAM_D7},
        .vsync_invert = true,
        .hsync_invert = false,
        .size = {
            .width = CAM_WIDTH,
            .high = CAM_HIGH,
        },
        .max_buffer_size = 4 * 1024,
        .task_stack = 1024 * 2,
        .task_pri = configMAX_PRIORITIES};

    /*!< 缓存区 */
    cam_config.frame1_buffer = (uint8_t *)malloc(IMAGE_BUF_SIZE);

    if (!cam_config.frame1_buffer)
    {
        ESP_LOGI(TAG, "malloc fail\n");
        vTaskDelete(NULL);
        return;
    }

    ESP_LOGI(TAG, "frame_buffer = %d", IMAGE_BUF_SIZE);
    ESP_LOGI(TAG, "[free mem good=%d;] \n", esp_get_free_heap_size());
    cam_init(&cam_config);

    sensor_t sensor;
    int camera_version = 0; /*!<If the camera version is determined, it can be set to manual mode */
    SCCB_Init(CAM_SDA, CAM_SCL);
    sensor.slv_addr = SCCB_Probe();
    ESP_LOGI(TAG, "sensor_id: 0x%x\n", sensor.slv_addr);

#ifdef CONFIG_CAMERA_OV2640
    camera_version = 2640;
#endif
#ifdef CONFIG_CAMERA_OV3660
    camera_version = 3660;
#endif
#ifdef CONFIG_CAMERA_AUTO
    /*!< If you choose this mode, Dont insert the Audio board, audio will affect the camera register read. */
#endif
    if (sensor.slv_addr == 0x30 || camera_version == 2640)
    { /*!< Camera: OV2640 */
        ESP_LOGI(TAG, "OV2640 init start...");
        // 输出 1600 * 1200 像素图片
        if (OV2640_Init(1, 0) != 0)
        {
            goto fail;
        }

        if (cam_config.mode.jpeg)
        {
            OV2640_JPEG_Mode();
        }
        else
        {
            OV2640_RGB565_Mode(false); /*!< RGB565 mode */
        }

        OV2640_Auto_Exposure(3);
        OV2640_Brightness(3);
        OV2640_Contrast(3);
        // OV2640_ImageWin_Set((800 / 2 - 480 / 2), (600 / 2 - 600 / 2), 480, 600);
        // OV2640_Rotate_180();
        OV2640_OutSize_Set(800, 600);
    }
    else if (sensor.slv_addr == 0x3C || camera_version == 3660)
    { /*!< Camera: OV3660 */

        sensor.slv_addr = 0x3C; /*!< In special cases, slv_addr may change */
        ESP_LOGI(TAG, "OV3660 init start...");
        ov3660_init(&sensor);
        sensor.init_status(&sensor);

        if (sensor.reset(&sensor) != 0)
        {
            goto fail;
        }

        if (cam_config.mode.jpeg)
        {
            sensor.set_pixformat(&sensor, PIXFORMAT_JPEG);
        }
        else
        {
            sensor.set_pixformat(&sensor, PIXFORMAT_RGB565);
        }

        /*!< TotalX gets smaller, frame rate goes up */
        /*!< TotalY gets smaller, frame rate goes up, vsync gets shorter */
        sensor.set_res_raw(&sensor, 0, 0, 2079, 1547, 8, 2, 1920, 800, CAM_WIDTH, CAM_HIGH, true, true);
        sensor.set_vflip(&sensor, 1);
        sensor.set_hmirror(&sensor, 1);
        sensor.set_pll(&sensor, false, 15, 1, 0, false, 0, true, 5); /*!< ov3660: 39 fps */
    }
    else
    {
        ESP_LOGE(TAG, "sensor is temporarily not supported\n");
        goto fail;
    }

    ESP_LOGI(TAG, "camera init done\n");
    CAMERA_SETUP_t setup_tmp = {0};

    cam_start();
    while (1)
    {

#if 0
        ESP_LOGI(TAG, "camera get ready\n");
        uint8_t *cam_buf = NULL;
        size_t s = cam_take(&cam_buf);
        ESP_LOGI(TAG, "cam_bufsize %d", s);
        cam_give(cam_buf);
#else
        ESP_LOGI(TAG, "camera get ready\n");
        ESP_LOGI(TAG, "[free mem=%d;] \n", esp_get_free_heap_size());
        /** 等待抓拍信号 */
        xEventGroupWaitBits(app_event_handle,
                            APP_EVENT_BIT_PHOTOGRAPH,
                            pdTRUE,
                            pdFALSE,
                            (portTickType)portMAX_DELAY);

        LED_CAM_0
        // get_camera_setup(&setup_tmp);
        // OV2640_Auto_Exposure(setup_tmp.Auto_Exposure);
        // OV2640_Light_Mode(setup_tmp.Light_Mode);
        // OV2640_Color_Saturation(setup_tmp.Color_Saturation);
        // OV2640_Brightness(setup_tmp.Brightness);
        // OV2640_Contrast(setup_tmp.Contrast);
        // OV2640_Special_Effects(setup_tmp.Special_Effects);
        // OV2640_Color_Bar(setup_tmp.Color_Bar);

        ESP_LOGW(TAG, "cam_start");
        /**
         * 抓拍3次清空以前的缓存
         */
        for (size_t i = 3; i > 0; i--)
        {
            uint8_t *cam_buf = NULL;
            size_t s = cam_take(&cam_buf);
            ESP_LOGW(TAG, "cam_buf %u size %u", i, s);
            ESP_LOGW(TAG, "size %u", s);

            if (s > 0 && i == 1)
            {
                ESP_LOGW(TAG, "cam_buf data %02X %02X %02X %02X %02X %02X", cam_buf[0], cam_buf[1], cam_buf[2], cam_buf[3], cam_buf[4], cam_buf[5]);
                ESP_LOGW(TAG, "cam_buf data %02X %02X %02X %02X %02X %02X", cam_buf[s - 5], cam_buf[s - 4], cam_buf[s - 3], cam_buf[s - 2], cam_buf[s - 1], cam_buf[s - 0]);

                /** 通过HTTP协议发送图片数据 */
                if (http_rest_image_jpeg(cam_buf, s) == ESP_OK)
                    xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_PHOTOGRAPH_SUCCESS);
                else
                {
                    xEventGroupSetBits(app_event_handle, APP_EVENT_BIT_PHOTOGRAPH_FAIL);
                    ESP_LOGW(TAG, "http rest image jpeg fail.");
                }
            }
            cam_give(cam_buf);
        }

        ESP_LOGW(TAG, "cam_end");
        LED_CAM_1
#endif
    }

fail:
    ESP_LOGE(TAG, "fail");
    free(cam_config.frame1_buffer);
    // free(cam_config.frame2_buffer);
    cam_deinit();
    // ESP_ERROR_CHECK(ESP_FAIL);
    vTaskDelete(NULL);
}
